package com.czk.shop.service;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.comon.czk.constant.ShopCode;
import com.comon.czk.entity.MQEntity;
import com.comon.czk.entity.Result;
import com.comon.czk.exception.CastException;
import com.comon.czk.utils.IDWorker;
import com.czk.api.ICouponService;
import com.czk.api.IGoodsService;
import com.czk.api.IOderService;
import com.czk.api.IUserService;
import com.czk.shop.mapper.TradeOrderMapper;
import com.czk.shop.pojo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;

/**
 * 订单的实现类
 *
 * @Author:ChenZhangKun
 * @Date: 2020/9/18 20:58
 */
@Slf4j
@Component
@Service(interfaceClass = IOderService.class)
public class IOrderServiceImpl implements IOderService {
    /**
     * 注入远程调用对象
     */
    @Reference
    private IGoodsService iGoodsService;
    @Reference
    private IUserService iUserService;
    @Reference
    private ICouponService iCouponService;
    @Autowired
    private IDWorker idWorker;
    @Autowired
    private TradeOrderMapper tradeOrderMapper;
    @Value("${mq.order.topic}")
    private String topic;
    @Value("${mq.order.tag.cancel}")
    private String tag;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Override
    public Result confirmOrder(TradeOrder tradeOrder) {
        // 1.校验订单
        this.checkOrder(tradeOrder);
        // 2.生成预订单
        Long orderId = this.savePreOrder(tradeOrder);
        try {
            // 3.扣减库存
            this.reduceGoodsNum(tradeOrder);
            // 4.扣减优惠券
            this.updateCouponStatus(tradeOrder);
            // 5.使用余额
            this.reduceMoneyPaid(tradeOrder);
            // 6.确认订单
            this.updateOrderStatus(tradeOrder);
            // 7.返回成功状态
            return new Result(ShopCode.SHOP_SUCCESS.getSuccess(), ShopCode.SHOP_SUCCESS.getMessage());
        } catch (Exception e) {
            // 1.确认订单失败,发送消息
            // 订单id,优惠券id,用户id,余额 商品id，商品的数量发送到消息队列中
            MQEntity mqEntity = new MQEntity();
            // 订单id
            mqEntity.setOrderId(orderId);
            // userId
            mqEntity.setUserId(tradeOrder.getUserId());
            // 钱
            mqEntity.setUserMoney(tradeOrder.getMoneyPaid());
            // 商品id
            mqEntity.setGoodsId(tradeOrder.getGoodsId());
            // 商品数量
            mqEntity.setGoodsNum(tradeOrder.getGoodsNumber());
            // 优惠券id
            mqEntity.setCouponId(tradeOrder.getCouponId());
            // 2.返回失败状态
            try {
                sendCancelOrder(topic, tag, tradeOrder.getOrderId().toString(), JSON.toJSONString(mqEntity));
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return new Result(ShopCode.SHOP_FAIL.getSuccess(), ShopCode.SHOP_FAIL.getMessage());
        }
    }

    /**
     * 发送错误消息
     *
     * @param topic        主题
     * @param tag          tag
     * @param toString     key
     * @param toJSONString 发送消息的json串
     */
    private void sendCancelOrder(String topic, String tag, String toString, String toJSONString) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
        // 创建消息
        Message message = new Message(topic, tag, toString, toJSONString.getBytes());
        // 发送消息
        rocketMQTemplate.getProducer().send(message);
    }

    /**
     * 更新订单状态
     *
     * @param tradeOrder
     */
    private void updateOrderStatus(TradeOrder tradeOrder) {
        // 已确认订单
        tradeOrder.setOrderStatus(ShopCode.SHOP_ORDER_CONFIRM.getCode());
        // 付款状态 已付款
        tradeOrder.setPayStatus(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY.getCode());
        // 付款时间
        tradeOrder.setConfirmTime(new Date());
        // 更新数据库
        int i = tradeOrderMapper.updateByPrimaryKey(tradeOrder);
        if (i <= 0) {
            CastException.cast(ShopCode.SHOP_ORDER_CONFIRM_FAIL);
        }
        log.info("订单：" + tradeOrder.getOrderId() + "确认订单成功");
    }

    /**
     * 扣减余额
     *
     * @param tradeOrder
     */
    private void reduceMoneyPaid(TradeOrder tradeOrder) {
        if (tradeOrder.getMoneyPaid() != null && tradeOrder.getMoneyPaid().compareTo(BigDecimal.ZERO) == 1) {
            TradeUserMoneyLog tradeUserMoneyLog = new TradeUserMoneyLog();
            // 封装余额实体
            tradeUserMoneyLog.setOrderId(tradeOrder.getOrderId());
            tradeUserMoneyLog.setUserId(tradeOrder.getUserId());
            tradeUserMoneyLog.setUseMoney(tradeOrder.getMoneyPaid());
            tradeUserMoneyLog.setMoneyLogType(ShopCode.SHOP_USER_MONEY_PAID.getCode());
            // 日志记录
            // 扣减余额
            Result result = iUserService.updateMoneyPaid(tradeUserMoneyLog);
            if (result.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess())) {
                CastException.cast(ShopCode.SHOP_USER_MONEY_REDUCE_FAIL);
            }
            log.info("订单：" + tradeOrder.getOrderId() + "扣减余额成功");
        }
    }

    /**
     * 扣减优惠券
     *
     * @param tradeOrder
     */
    private void updateCouponStatus(TradeOrder tradeOrder) {
        // 拿到优惠券id
        Long couponId = tradeOrder.getCouponId();
        // 查询优惠券
        TradeCoupon coupon = iCouponService.findOne(couponId);
        // 设置订单信息
        // 订单id
        coupon.setOrderId(tradeOrder.getOrderId());
        // 优惠券被使用
        coupon.setIsUsed(ShopCode.SHOP_COUPON_ISUSED.getCode());
        // 设置使用时间
        coupon.setUsedTime(new Date());
        // 更新优惠券状态
        Result result = iCouponService.updateCouponStatus(coupon);
        if (result.getSuccess().equals(ShopCode.SHOP_FAIL)) {
            CastException.cast(ShopCode.SHOP_COUPON_USE_FAIL);
        }
        log.info("订单：" + tradeOrder.getOrderId() + "使用了优惠券");
    }

    /**
     * 扣减库存
     *
     * @param tradeOrder
     */
    private void reduceGoodsNum(TradeOrder tradeOrder) {
        TradeGoodsNumberLog goodsNumberLog = new TradeGoodsNumberLog();
        // 订单id
        goodsNumberLog.setOrderId(tradeOrder.getOrderId());
        // 商品id
        goodsNumberLog.setGoodsId(tradeOrder.getGoodsId());
        // 商品数量
        goodsNumberLog.setGoodsNumber(tradeOrder.getGoodsNumber());
        Result result = iGoodsService.reduceNum(goodsNumberLog);
        if (result.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess())) {
            CastException.cast(ShopCode.SHOP_REDUCE_GOODS_NUM_FAIL);
        }
        log.info("订单" + tradeOrder.getOrderId() + "扣减库存成功");
    }

    /**
     * 生成预订单
     *
     * @param tradeOrder
     * @return
     */
    private Long savePreOrder(TradeOrder tradeOrder) {
        // 设置订单状态为不可见
        tradeOrder.setOrderStatus(ShopCode.SHOP_ORDER_NO_CONFIRM.getCode());
        // 生成订单id
        // 雪花算法生成订单id
        long id = idWorker.nextId();
        tradeOrder.setOrderId(id);
        BigDecimal shippingFee = this.calculateShippingFee(tradeOrder.getOrderAmount());
        if (tradeOrder.getShippingFee().compareTo(shippingFee) != 0) {
            // 运费不合法
            CastException.cast(ShopCode.SHOP_ORDER_SHIPPINGFEE_INVALID);
        }
        // 核算订单总金额是否合法
        BigDecimal orderAmount = tradeOrder.getGoodsPrice().multiply(new BigDecimal(tradeOrder.getGoodsNumber()));
        // 加上运费
        orderAmount.add(shippingFee);
        // 比对金额是否正确
        if (tradeOrder.getOrderAmount().compareTo(orderAmount) != 0) {
            CastException.cast(ShopCode.SHOP_ORDERAMOUNT_INVALID);
        }
        // 判断用户是否使用余额
        BigDecimal moneyPaid = tradeOrder.getMoneyPaid();
        if (moneyPaid != null) {
            // 订单余额是否合法
            int i = moneyPaid.compareTo(BigDecimal.ZERO);
            // 所用余额为负数
            if (i == -1) {
                CastException.cast(ShopCode.SHOP_MONEY_PAID_LESS_ZERO);
            }
            // 余额大于0
            if (i == 1) {
                // 插卡用户在数据库的余额
                TradeUser user = iUserService.findOne(tradeOrder.getUserId());
                if (moneyPaid.compareTo(new BigDecimal(user.getUserMoney())) == 1) {
                    // 所用余额大于在数据库中的余额
                    CastException.cast(ShopCode.SHOP_MONEY_PAID_INVALID);
                }
            } else {
                // 不用余额
                tradeOrder.setMoneyPaid(BigDecimal.ZERO);
            }
        }
        // 判断用户是否使用优惠券
        // 得到优惠券id
        Long couponId = tradeOrder.getCouponId();
        if (couponId != null) {
            // 查询优惠券
            TradeCoupon tradeCoupon = iCouponService.findOne(couponId);
            // 优惠券是否存在
            if (tradeCoupon == null) {
                CastException.cast(ShopCode.SHOP_COUPON_NO_EXIST);
            }
            // 判断优惠券是否被使用
            if (tradeCoupon.getIsUsed().intValue() == ShopCode.SHOP_COUPON_ISUSED.getCode().intValue()) {
                CastException.cast(ShopCode.SHOP_COUPON_ISUSED);
            }
            // 设置优惠券的金额
            tradeOrder.setCouponPaid(tradeCoupon.getCouponPrice());
        } else {
            // 没有传递优惠券
            tradeOrder.setCouponPaid(BigDecimal.ZERO);
        }
        // 核算订单支付金额
        // 订单总金额-余额-优惠券金额
        BigDecimal payAmount = tradeOrder.getOrderAmount().subtract(tradeOrder.getMoneyPaid()).subtract(tradeOrder.getCouponPaid());
        tradeOrder.setPayAmount(payAmount);
        // 设置下单时间
        tradeOrder.setAddTime(new Date());
        // 保存订单到数据库
        tradeOrderMapper.insert(tradeOrder);
        // 返回订单id
        return id;
    }

    /**
     * 核算运费
     *
     * @param orderAmount
     * @return
     */
    private BigDecimal calculateShippingFee(BigDecimal orderAmount) {
        if (orderAmount.compareTo(new BigDecimal("100")) == 1) {
            // 不要运费
            return BigDecimal.ZERO;
        } else {
            // 十元运费
            return new BigDecimal("10");
        }
    }

    /**
     * 校验订单
     *
     * @param tradeOrder
     */
    private void checkOrder(TradeOrder tradeOrder) {
        // 1. 校验订单是否存在
        if (tradeOrder == null) {
            CastException.cast(ShopCode.SHOP_ORDER_INVALID);
        }
        // 校验订单中商品是否存在
        TradeGoods tradeGoods = iGoodsService.findOne(tradeOrder.getGoodsId());
        if (tradeGoods == null) {
            // 商品不存在
            CastException.cast(ShopCode.SHOP_GOODS_NO_EXIST);
        }
        // 校验下单用户是否存在
        TradeUser tradeUser = iUserService.findOne(tradeOrder.getUserId());
        if (tradeUser == null) {
            CastException.cast(ShopCode.SHOP_USER_NO_EXIST);
        }
        // 校验订单金额是否合法
        if (tradeOrder.getGoodsPrice().compareTo(tradeGoods.getGoodsPrice()) != 0) {
            CastException.cast(ShopCode.SHOP_GOODS_PRICE_INVALID);
        }
        // 校验订单的数量是否合法
        // 购买数小于库存数
        if (tradeOrder.getGoodsNumber() > tradeGoods.getGoodsNumber()) {
            CastException.cast(ShopCode.SHOP_GOODS_NUM_NOT_ENOUGH);
        }
        log.info("校验订单通过");
    }
}
